//
//  VCDownloadHTTPConnection.m
//  VCDemo
//
//  Created by 肖康龙 on 2017/9/1.
//  Copyright © 2017年 vsoontech. All rights reserved.
//

#import "VCDownloadHTTPConnection.h"
#import "VCDowmload.h"
#import "VCDownloadManger.h"
#import "VCInformationTool.h"


@interface VCDownloadHTTPConnection ()

/**是否结束阻塞*/
@property (nonatomic,assign)BOOL isEnd;
/**要加载的路径*/
@property (nonatomic,strong)NSString *fileName;
@end


@implementation VCDownloadHTTPConnection

//static NSInteger VC_sequence;//m3u8序列号
//static NSFileManager *VC_fm;//文件句柄




//扩展HTTPServer支持的请求类型，默认支持GET，HEAD，不支持POST
//请求的
- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)relativePath
{
    //    VCNSLog(@"我看看你请求了什么%@",relativePath);
    if ([@"POST" isEqualToString:method])
    {
        return YES;
    }
    return [super supportsMethod:method atPath:relativePath];
}

//处量返回的response数据
//返回的
- (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
{
//    if ([path containsString:@"m3u8"]) {
//        [self assemblyM3U8Data];
//    }
    VCNSLog(@"看看请求了那些%@",path);
    if ([path containsString:@"m3u8"]) {//请求m3u8那就算了
        
        return [super httpResponseForMethod:method URI:path];
    }
    self.fileName = path;
    
    [[NSNotificationCenter defaultCenter] postNotificationName:VCDownloadSendDownloadNotification object:nil userInfo:@{PLAY_NUM_TS:@([self getTsNumWithPath:path])}];//发通知去下载
    
    self.isEnd = NO;//重置为No
    
    [self checkDownloadComplete];//检查下载完成没有
    while (!self.isEnd) {
        sleep(1);
        [self checkDownloadComplete];//检查下载完成没有
    }
    VCNSLog(@"看看请求了那些%@ 之后的",path);
    return [super httpResponseForMethod:method URI:path];
}
/**检查有没有下载完毕*/
-(void)checkDownloadComplete{
    NSArray *array = [[VCInformationTool getTSFileArray] copy];
    for (NSString *fileName in array) {
        if ([fileName containsString:self.fileName]) {
            self.isEnd = YES;
            break;
        }
    }
    
}


/**获取当前ts序号*/
-(NSInteger)getTsNumWithPath:(NSString *)path{
    
    NSRange rang = [path localizedStandardRangeOfString:@"."];
    
    NSString *numTs = [path substringFromIndex:rang.location+1];
    
    rang = [numTs localizedStandardRangeOfString:@"."];
    numTs = [numTs substringToIndex:rang.location];
    
    return [numTs integerValue];
}

///**组装m3u8*/
//-(void)assemblyM3U8Data{
//    
//    NSString *m3u8 = [NSString stringWithFormat:@"#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-TARGETDURATION:10\n#EXT-X-MEDIA-SEQUENCE:%ld\n",VC_sequence];
//    
//    NSString *path_movie = [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0] stringByAppendingPathComponent:@"Downloads"] stringByAppendingPathComponent:@"movie1"];
//    NSString *path_ts;
//    
//    NSArray *tsFileList = [[VCInformationTool getFileDict] objectForKey:@"fileList"];
//    int duration = 0;
//    for (NSInteger i = VC_sequence ; i < VC_sequence + 3 && i < tsFileList.count; i++) {
//        
//        NSDictionary *tsFile = tsFileList[i];
//        
//        duration = [[tsFile objectForKey:@"duration"] intValue] == 0 ? 10 : [[tsFile objectForKey:@"duration"] intValue];
//        m3u8 = [NSString stringWithFormat:@"%@#EXTINF:%i\n%@.ts\n",m3u8,duration,[tsFile objectForKey:@"fileId"]];
//        
//        if (i == tsFileList.count -1) {
//            m3u8 = [NSString stringWithFormat:@"%@#EXT-X-ENDLIST",m3u8];
//        }
//        
//        path_ts = [path_movie stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.ts",[tsFile objectForKey:@"fileId"]]];
//        if (![VC_fm fileExistsAtPath:path_ts isDirectory:nil]) {//如果没有下载到就先退出
//            if (VC_sequence == 0) {//第一次,就继续
//                break;
//            }else{
//                return;
//            }
//        }
//    }
//    
//    
//    
//    VC_sequence++;
//    if (VC_fm == nil) {
//        VC_fm = [[NSFileManager alloc] init];
//    }
//    
//    //创建M3U8的链接地址
//    NSString *path = [path_movie stringByAppendingPathComponent:@"movie.m3u8"];
//    //拼接完成，存储到本地
//    NSMutableData *writer = [[NSMutableData alloc] init];
//    
//    //判断m3u8是否存在,已经存在的话就不再重新创建
//    if ([VC_fm fileExistsAtPath:path isDirectory:nil]) {
//        //存在这个链接
//        VCNSLog(@"存在这个链接");
//    } else {
//        //不存在这个链接
//        NSString *saveTo = [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0] stringByAppendingPathComponent:@"Downloads"] stringByAppendingPathComponent:@"movie1"];
//        BOOL isS = [VC_fm createDirectoryAtPath:saveTo withIntermediateDirectories:YES attributes:nil error:nil];
//        if (isS) {
//            VCNSLog(@"创建目录成功");
//        } else {
//            VCNSLog(@"创建目录失败");
//        }
//    }
//    [writer appendData:[m3u8 dataUsingEncoding:NSUTF8StringEncoding]];
//    BOOL bSucc = [writer writeToFile:path atomically:YES];
//    if (bSucc) {
//        //成功
//        VCNSLog(@"M3U8数据保存成功");
//    } else {
//        //失败
//        VCNSLog(@"M3U8数据保存失败");
//    }
//    VCNSLog(@"新数据\n%@", m3u8);
//    
//}



//处理POST请求提交的数据流(下面方法是改自 Andrew Davidson的类)
- (void)processDataChunk:(NSData *)postDataChunk
{
    VCNSLog(@"processDataChunk function called");
    //multipartData初始化不放在init函数中, 当前类似乎不经init函数初始化
    if (multipartData == nil) {
        multipartData = [[NSMutableArray alloc] init];
    }
    
    //处理multipart/form-data的POST请求中Body数据集中的表单值域并创建文件
    if (!postHeaderOK)
    {
        //0x0A0D: 换行符
        UInt16 separatorBytes = 0x0A0D;
        NSData* separatorData = [NSData dataWithBytes:&separatorBytes length:2];
        
        NSUInteger l = [separatorData length];
        for (int i = 0; i < [postDataChunk length] - l; i++)
        {
            //每次取两个字节 比对下看看是否是换行
            NSRange searchRange = {i, l};
            //如果是换行符则进行如下处理
            if ([[postDataChunk subdataWithRange:searchRange] isEqualToData:separatorData])
            {
                //获取dataStartIndex标识的上一个换行位置到当前换行符之间的数据的Range
                NSRange newDataRange = {dataStartIndex, i - dataStartIndex};
                //dataStartIndex标识的上一个换行位置到移到当前换行符位置
                dataStartIndex = (int)(i + l);
                i += l - 1;
                //获取dataStartIndex标识的上一个换行位置到当前换行符之间的数据
                NSData *newData = [postDataChunk subdataWithRange:newDataRange];
                //如果newData不为空或还没有处理完multipart/form-data中表单变量值域则继续处理剩下的表单值域数据
                if ([newData length] || ![self isBeginOfOctetStream])
                {
                    if ([newData length]) {
                        [multipartData addObject:newData];
                    }
                }
                else
                {
                    //将标识处理完multipart/form-data中表单变量值域的postHeaderOK变量设置为TRUE;
                    postHeaderOK = TRUE;
                    //这里暂时写成硬编码 弊端:每次增加表单变量都要改这里的数值
                    //获取Content-Disposition: form-data; name="xxx"; filename="xxx"
                    NSString* postInfo = [[NSString alloc] initWithBytes:[[multipartData objectAtIndex:4] bytes]
                                                                  length:[[multipartData objectAtIndex:4] length]
                                                                encoding:NSUTF8StringEncoding];
                    VCNSLog(@"postInfo is:%@", postInfo);
                    NSArray* postInfoComponents = [postInfo componentsSeparatedByString:@"; filename="];
                    postInfoComponents = [[postInfoComponents lastObject] componentsSeparatedByString:@"\""];
                    VCNSLog(@"postInfoComponents0 :%@",postInfoComponents);
                    if ([postInfoComponents count]<2)
                    {
                        return;
                    }
                    
                    postInfoComponents = [[postInfoComponents objectAtIndex:1] componentsSeparatedByString:@"\\"];
                    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
                    NSString* filename = [documentPath stringByAppendingPathComponent:[postInfoComponents lastObject]];
                    VCNSLog(@"filename :%@",filename);
                    NSRange fileDataRange = {dataStartIndex, [postDataChunk length] - dataStartIndex};
                    [[NSFileManager defaultManager] createFileAtPath:filename contents:[postDataChunk subdataWithRange:fileDataRange] attributes:nil];
                    NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:filename];
                    if (file)
                    {
                        [file seekToEndOfFile];
                        [multipartData addObject:file];
                    }
                    
                    break;
                }
            }
        }
    }
    else //表单值域已经处理过了 这之后的数据全是文件数据流
    {
        [(NSFileHandle*)[multipartData lastObject] writeData:postDataChunk];
    }
    
    float uploadProgress = (double)requestContentLengthReceived / requestContentLength;
    //实际应用时 当前类的实例是相当于单例一样被引用(因为只被实例化一次)
    if (uploadProgress >= 1.0) {
        postHeaderOK = NO;
        multipartData = nil;
    }
    //    [[NSNotificationCenter defaultCenter] postNotificationName:UPLOAD_FILE_PROGRESS object:[NSNumber numberWithFloat:uploadProgress] userInfo:nil];
}
- (void)prepareForBodyWithSize:(UInt64)contentLength
{
    VCNSLog(@"%llu",contentLength);
    VCNSLog(@"%llu",contentLength);
}

//检查是否已经处理完了multipart/form-data表单中的表单变量
- (BOOL) isBeginOfOctetStream
{
    NSString *octetStreamFlag = @"Content-Type: application/octet-stream";
    NSString *findData = [[NSString alloc] initWithData:(NSData *)[multipartData lastObject] encoding:NSUTF8StringEncoding];
    
    for (NSData *d in multipartData) {
        NSString *temp = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding] ;
        VCNSLog(@"multipartData items: %@", temp);
    }
    //如果已经处理完了multipart/form-data表单中的表单变量
    if ( findData != nil && [findData length] > 0 )
    {
        VCNSLog(@"findData is :%@\n octetStreamFlag is :%@", findData, octetStreamFlag);
        if ([octetStreamFlag isEqualToString:findData]) {
            VCNSLog(@"multipart/form-data 变量值域数据处理完毕");
            return YES;
        }
        return NO;
    }
    return NO;
    
}


@end
